"use strict";

let user = {
  name: "Jason",
  age: 19,
  grade: [
    {
      name: "js",
      score: 99,
    },
    {
      name: "docker",
      score: 100,
    },
  ],
  average() {
    let total = this.grade.reduce((t, l) => t + l.score, 0);
    return `${this.name}的平均成绩是: ${total / this.grade.length}`;
  },
};
// console.log(user.average());

user.get = function () {
  return `${this.name}的年龄是${this.age}`;
};

delete user.name; // 删除对象中的属性
// console.log(user.name);

let data = {
  hobby: "CF",
  tel: "666",
};
// Object.freeze(data); // freeze有冻结对象的意思，你改不了当前对象
data.tel = 30;
// console.log(data);

let user1 = { name: "Jay" };
function show() {
  user1.age = 30;
  // console.log(user1);
}
show();
// console.log(user1);

function upload(params) {
  let config = {
    type: "*.jpg, *.png",
    size: 10000,
  };
  config = { ...config, ...params };
  //   console.log(config);
}
upload({ size: 99 });

function user2({ name, age }) {
  // console.log(name, age);
}
user2({ name: "Jason", age: 19 });

let web = { name: "hdr", url: "houdunren.com" };
let { name: bb, url: aa } = web; //左边是元素数据，右边是你的变量名
// console.log(bb);

// 传入个对象，一样可以结构，相当于 let {sex, age} = {sex:"男", age: 29}
function hd(name, { sex, age }) {
  // console.log(name, sex, age);
}
hd("险峻", { sex: "男", age: 19 });

let hd1 = {};
hd1.name = "jason";
hd1["age"] = 30;
delete hd1.name;
// 判断是否有该属性只检测自己
// console.log(hd1.hasOwnProperty("age"));

let a = {
  name: "叶湘伦",
};

let b = {
  desc: "jay",
};
Object.setPrototypeOf(a, b); // 将a的原型设置为b，也就是说b是a的父亲
// console.log("我是desc", "desc" in a); // 检测 desc属性是否在a中，一直沿着原型链找

function oss(options) {
  // 仅仅判断当前自身的对象是否有传入host属性
  if (!options.hasOwnProperty("host")) {
    console.log("no");
    // throw new Error("pls set host!")
  }
}
// oss({ user: "admin" });

/* 经典面试题
  const obj = {
    a: 0,
  };
  obj["1"] = 0;
  obj[++obj.a] = obj.a++;
  const values = Object.values(obj);
  obj[values[1]] = obj.a;
  console.log(obj);


  let aaa = new Array();
  aaa[0] = 1;
  aaa["0"] = 2;
  ++aaa[0];
  console.log(aaa["0"]);
  console.log(aaa[0]);
*/

let lessons = [
  {
    title: "Mysql多表查询",
    category: "mysql",
  },
  {
    title: "Java",
    category: "javaJkd8",
  },
  {
    title: "nodes",
    category: "node129",
  },
];

let res = lessons.reduce((obj, cur, index) => {
  obj[`${cur["category"]}-${index + 1}`] = cur;
  return obj;
}, {});

// console.log(JSON.stringify(res, null, 2));

function upload1(params) {
  let options = {
    size: 1000,
  };
  // OBject的assign合并，将后面的合并到options中
  return Object.assign(options, params);
}
// console.log(upload1({ size: 200, type: "lol" }));

let hd2 = ["后盾人", "2022"];
// for in 可以操作对象和数组，for of只能操作迭代对象
for (const key in hd2) {
  // console.log(hd2[key]);
}

let hd3 = {
  name: "LOl",
  age: 30,
};
// console.log(Object.keys(hd3));

for (const iterator of Object.keys(hd3)) {
  // console.log(iterator);
}

// 对象浅拷贝
let hd4 = { name: "jason", url: "houdunre.com", xxx: { a: 1 } };
let hd4Obj = Object.assign({}, hd4);
// console.log(hd4Obj);

// 深拷贝，嵌套的那种,嵌套数组或者是对象
let hd5 = {
  name: "xxx",
  age: 30,
  arr: [],
  objxxx: {
    english: 80,
  },
};
// console.log(JSON.stringify(Object.entries(hd5), null, 2));
function copy(data) {
  // 判断是不是Array，是的话用[] 否则用 {}
  let res = data instanceof Array ? [] : {};
  for (const [k, v] of Object.entries(data)) {
    // 判断值是对象还是数组？ 无论是对象或者数组 typeof 都是object，如果是的话就递归调用
    res[k] = typeof v == "object" ? copy(v) : v;
  }
  return res;
}
let hd6 = copy(hd5);
hd5.arr.push("abc");
hd6.arr.push("xxx");

hd6.name = "我是hd6";
// console.log(JSON.stringify(hd5, null, 2));
// console.log(JSON.stringify(hd6, null, 2));

// 工厂函数
function userInfo(name, age) {
  return {
    name,
    age,
    show() {
      // console.log(this.name + `-houdunren.com`);
    },
    info() {
      // console.log(`${this.name}的年龄是${this.age}`);
    },
  };
}
let xj = userInfo("向军", 20);
// xj.show();

// 构造函数
function UserInfo(name) {
  this.name = name;
  this.show = function () {
    // console.log(this.name);
  };
}

let js = new UserInfo("hahha");
// js.show(); // 当前是js调用的所以this指向 UserInfo这个对象
// let func = js.show;
// func(); // 这种调用是全局调用，this指向windows

// 使用构造函数创建数据
let o = new Object();
o.name = "后盾人hahha";
// console.log(o);

let n = new Number(1);
// console.log(n.valueOf());

let t = new Boolean(true);
// console.log(t.valueOf());

let str = new String("How are you?");
// console.log(str.valueOf());
// console.log(str.toUpperCase());

let r = new RegExp("\\d+");
// console.log(r.valueOf());
// console.log(r.test("999")); // true

function func() {}
// console.log(func.constructor); // Function

let User = new func.constructor(
  "name",
  `this.name = name; this.show = function() {
  console.log(this.name);
}`
);

let ljh = new User("无敌");
// ljh.show();

// 抽象
function User12(name, age) {
  let data = { name, age };
  let info = function () {
    return data.age > 50 ? "老年" : "青年";
  };
  this.show = function () {
    // console.log(data.name + info());
  };
}

let xj1 = new User12("xj", 60);
this.name = "jason";
xj1.info = function () {
  return "";
};
xj1.show();

// 什么事对象的属性特征？
const user3 = {
  name: "李嘉辉",
  age: 30,
};
// 可以获得某个对象中某个属性的一些描述，默认都是true
// console.log(
//   JSON.stringify(Object.getOwnPropertyDescriptor(user3, "name"), null, 2)
// );
// 如果没有site属性就相当于是添加属性
Object.defineProperty(user3, "site", {
  value: "哈哈哈",
  writable: true, //是否可以读写？
  enumerable: false, //是否可以遍历
  configurable: true, //是否可以删除或者重新设置？
});
// console.log(user3);
// console.log(Object.keys(user3));

// 不允许往对象中添加属性
Object.preventExtensions(user3); // prevent防止，extensions扩张
if (Object.isExtensible(user3)) {
  user3.hobby = "plya basketball";
  // console.log(user3);
}

// Object.seal(); 封闭对象
const jasonData = {
  name: "Vue3",
  age: 3,
};
Object.seal(jasonData); // 密封起来
if (!Object.isSealed(jasonData)) {
  jasonData.phone = "13189030604";
  // console.log(jasonData);
}
// console.log(jasonData);

// Object.freeze(); 冻结对象
const dataFreez = {
  name: "react",
  age: 20,
};
Object.freeze(dataFreez); // 冻结数组
// console.log(Object.isFrozen(dataFreez)); // 检验是否是冻结状态

// 使用访问器保护数据, 当访问器和普通属性同时存在的时候访问器的优先级是高的
const user4 = {
  data: { name: "后盾人", age: 30 },
  set age(val) {
    if (typeof val != "number" || val < 10 || val > 100) {
      throw new Error("年龄格式错误!!");
    }
    this.data.age = val;
  },

  get age() {
    return this.data.age + "岁";
  },
};

// 直接设置写 = 就可以
user4.age = 19;
// console.log(user4.age); // 访问的话就是这样

let lesson = {
  lists: [
    {
      name: "js",
      price: 100,
    },
    {
      name: "mysql",
      price: 123,
    },
    {
      name: "vue.js",
      price: 100,
    },
  ],

  get total() {
    return this.lists.reduce((t, l) => t + l.price, 0);
  },
};
// console.log(lesson.total);

const web1 = {
  name: "后盾人",
  url: "houdunren.com",
  get site() {
    return `${this.name}的网址是${this.url}`;
  },
  set site(val) {
    [this.name, this.url] = val.split(",");
  },
};
web1.site = "开源产品,www.baidu.com";
// console.log(web1.site);

// token Set
/*
  let Request = {
    set token(content) {
      localStorage.setItem("token", content);
    },
    get token() {
      return localStorage.getItem("token") ? this.token : alert("请登录");
    },
  };

  Request.token = "130271936217dhwiadnwiuadgi2";
  console.log(Request.token);
*/

// 构造函数使用访问器
const DATA = Symbol();
class Person {
  constructor(name, age) {
    this[DATA] = { name, age };
  }
  set name(val) {
    if (val.trim() == "" || val.length > 20) throw new Error("用户不合法");
    this[DATA].name = val;
  }

  set age(val) {
    this[DATA].age = val;
  }

  get name() {
    return this[DATA].name;
  }

  get age() {
    return this[DATA].age;
  }
}

let theshy = new Person("theshy", 24);
theshy.name = "rookie";
// console.log(theshy.name);

// 什么事Proxy代理拦截？
const proxxxx = { name: "我是代理对象" };
const proxy = new Proxy(proxxxx, {
  get(obj, property) {
    return obj[property];
  },

  set(obj, property, val) {
    obj[property] = val;
    return true;
  },
});

console.log(proxy.name);
console.log(proxy);

// 使用代理来控制函数
function factorial(num) {
  return num == 1 ? 1 : num * factorial(num - 1);
}

let proxyFcun = new Proxy(factorial, {
  apply(func, obj, args) {
    console.time("run");
    func.apply(this, args);
    console.timeEnd("run");
  },
});
proxyFcun.apply({}, [1000]);

// 数组使用Proxy代理拦截操作, 就是加工数据的，对你一些要求进行加加工要求然后返回
const lessonsClass = [
  {
    title: "Mysq多表查询随意操作",
    category: "mysql",
  },
  {
    title: "世界第一ADC简自豪",
    category: "uzi",
  },
  {
    title: "Micheal Jordan is my hero",
    category: "Jordan",
  },
];

const proxyLessonsCalss = new Proxy(lessonsClass, {
  get(arr, key) {
    console.log(key);
    const len = 5;
    const title = arr[key].title;
    arr[key].title =
      title.length > len ? title.substr(0, len) + ".".repeat(3) : title;
    return arr[key];
  },
});

console.log(JSON.stringify(proxyLessonsCalss[0], null, 2));

const data1 = [{ name: "CF" }];
console.log(JSON.stringify(data1, null, 2));

// 自定义Json数据,当你调用json.stringily的时候返回的就是toJSON的return
let hd7 = {
  title: "jsWeb",
  name: "master",
  teacher: {
    name: "鸣人",
  },
  toJSON() {
    return {
      title: this.title,
      name: this.teacher.name,
    };
  },
};

console.log(JSON.stringify(hd7));
